/**
 * 
 */
package edu.cmu.mism.dgjava.algorithm.impl;

import edu.cmu.mism.dgjava.data.models.option.BaseType;

/**
 * @author Ankit
 * 
 */
/**
 * @author Ankit
 *
 */
public abstract class BinomialAlg extends OptionsAlg {

	protected int numberOfTreeSteps = 0;

	protected double expectedYield = 0.0;
	protected double actualOptionPrice = 0.0;

	protected double deltaTime = 0.0;
	protected double upFactor = 0.0;
	protected double downFactor = 0.0;
	protected double growthFactor = 0.0;
	protected double probabilityOfUp = 0.0;

	protected TreeNode[][] treeNode;
	protected TreeNode copiedTreeNode[][];

	public BinomialAlg(Object underlyingModel, Object pricingModel) {
		super(underlyingModel, pricingModel);

	}

	/* (non-Javadoc)
	 * @see edu.cmu.mism.dgjava.algorithm.impl.OptionsAlg#calculateTheta()
	 */
	protected void calculateTheta() {

		theta = (treeNode[2][1].optionPrice - treeNode[0][0].optionPrice)
				/ (2 * (deltaTime));
		theta /= 365;
	}

	
	/* (non-Javadoc)
	 * @see edu.cmu.mism.dgjava.algorithm.impl.OptionsAlg#calculateGamma()
	 */
	protected void calculateGamma() {

		double h = 0.5 * (treeNode[2][2].stockPrice - treeNode[2][0].stockPrice);

		gamma = (((treeNode[2][2].optionPrice - treeNode[2][1].optionPrice) / (treeNode[2][2].stockPrice - treeNode[0][0].stockPrice)) - ((treeNode[2][1].optionPrice - treeNode[2][0].optionPrice) / (treeNode[0][0].stockPrice - treeNode[2][0].stockPrice)))
				/ h;
	}

	
	/* (non-Javadoc)
	 * @see edu.cmu.mism.dgjava.algorithm.impl.OptionsAlg#calculateDelta()
	 */
	protected void calculateDelta() {

		delta = (treeNode[1][1].optionPrice - treeNode[1][0].optionPrice)
				/ (stockPrice * (upFactor - downFactor));

	}

	/**
	 * Calculate the option price based on type: Put or Call
	 * 
	 * @param stockPrice
	 * @param strikePrice
	 * @param comparer
	 * @return
	 */
	protected double calculateOptionPrice(double stockPrice, double strikePrice,
			double comparer) {
		
		if(type.getValue() == BaseType.CALL_VALUE){
			return max(stockPrice
					- strikePrice, comparer);
		} else {
			return max(strikePrice
					- stockPrice, comparer);
		}
	
	}
	
	/**
	 * Copy the value of treeNode actually calculated in the new data structures.
	 * These will be required in generating graphs.
	 */
	protected void copyDuplicateTreeNode() {
		
		copiedTreeNode = new TreeNode[numberOfTreeSteps + 1][];
		
		for (int i = numberOfTreeSteps; i >= 0; i--) {
			
			copiedTreeNode[i] = new TreeNode[numberOfTreeSteps + 1];

			for (int j = 0; j <= i; j++) {
				
				copiedTreeNode[i][j] = new TreeNode();
				copiedTreeNode[i][j].stockPrice = treeNode[i][j].stockPrice;
				copiedTreeNode[i][j].optionPrice = treeNode[i][j].optionPrice;
			}
		}
	}
	
	/**
	 * 
	 * @return the tree nodes generated for calculating the option and stock prices.
	 * The copied tree node contains the actual value calculated. The treeNode variable 
	 * contains the values calculated initially. 
	 * But, these values changed while calculating the value of greek letters.
	 */
	public TreeNode[][] getTreeNode() {
		return copiedTreeNode;
	}
	
	/**
	 *  Calculate all the initial parameters which will be required to calculate the option prices.
	 */
	protected void calculateOptionsParameters() {


		deltaTime = timeToExpiration / numberOfTreeSteps;
		upFactor = Math.pow(Math.E, volatility * Math.sqrt(deltaTime));

		downFactor = 1.0 / upFactor;

		growthFactor = Math.pow(Math.E, (riskFreeRate - expectedYield)
				* deltaTime);

		probabilityOfUp = (growthFactor - downFactor) / (upFactor - downFactor);
		
	}

}
